package com.ruibang.glass.material.service.impl.cl;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.domain.camunda.BpmProcessInstanceStatus;
import com.ruibang.glass.material.constant.Constants;
import com.ruibang.glass.material.constant.MaterialStatusCode;
import com.ruibang.glass.material.domain.req.ycl.ManagementInventoryReq;
import com.ruibang.glass.material.entity.MaterialALLInventoryManagement;
import com.ruibang.glass.material.entity.MaterialInventoryItem;
import com.ruibang.glass.material.entity.cl.MaterialCLManagementInventory;
import com.ruibang.glass.material.feign.CamundaApi;
import com.ruibang.glass.material.feign.PurchaseApi;
import com.ruibang.glass.material.mapper.cl.MaterialCLManagementInventoryMapper;
import com.ruibang.glass.material.service.GMaterialALLInventoryManagementService;
import com.ruibang.glass.material.service.MaterialInventoryItemService;
import com.ruibang.glass.material.service.cl.MaterialCLManagementInventoryService;
import com.ruibang.glass.material.service.impl.CommonService;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.common.constant.CommonConstant;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 物料管理入库表 服务实现类
 * </p>
 *
 * @author mameng
 * @since 2024-04-01
 */
@Service
public class MaterialCLManagementInventoryServiceImpl extends ServiceImpl<MaterialCLManagementInventoryMapper,
        MaterialCLManagementInventory> implements MaterialCLManagementInventoryService {

    @Autowired
    private CommonService commonService;

    @Autowired
    private CamundaApi camundaApi;

    @Autowired
    private RedisSingleService redisService;

    @Autowired
    private GMaterialALLInventoryManagementService materialALLInventoryManagementService;

    @Autowired
    private MaterialInventoryItemService inventoryItemService;

    @Autowired
    private PurchaseApi purchaseApi;
    /**
     * 列表计算
     *
     * @param managementInventoryReq
     * @return
     */
    @Override
    public IPage<MaterialCLManagementInventory> getPage(ManagementInventoryReq managementInventoryReq) {

        IPage<MaterialCLManagementInventory> page = baseMapper.queryPage(new Page<>(managementInventoryReq.getPageNo(), managementInventoryReq.getPageSize()), managementInventoryReq);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return page;
        }

        Map<Object, Object> userMap = redisService.hmget(RedisKey.USER_GROUP_TYPE);
        List<String> businessKeys = page.getRecords().stream().map(MaterialCLManagementInventory::getId).collect(Collectors.toList());
        Map<String, BpmProcessInstanceStatus> processMap = null;
        //获取业务流程状态
        ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(businessKeys);
        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
            processMap = resultBody.getData().stream().collect(Collectors.toMap(bp -> bp.getBusinessKey(), bp -> bp, (bp1, bp2) -> bp1));
        }

        for (MaterialCLManagementInventory inventory : page.getRecords()) {
            if(userMap!=null){
                inventory.setInspectorName(userMap.get(inventory.getInspectorId())==null?null:userMap.get(inventory.getInspectorId()).toString());
                inventory.setPreparerName(userMap.get(inventory.getPreparerId())==null?null:userMap.get(inventory.getPreparerId()).toString());
                inventory.setArrivalPersonName(userMap.get(inventory.getArrivalPersonId())==null?null:userMap.get(inventory.getArrivalPersonId()).toString());
                inventory.setWarehouseSupervisor(userMap.get(inventory.getWarehouseSupervisor()) == null ? null : userMap.get(inventory.getWarehouseSupervisor()).toString());
            }
            if (processMap != null) {
                BpmProcessInstanceStatus instance = processMap.get(inventory.getId());
                if(instance!=null){
                    inventory.setProcessId(instance.getProcessInstanceId());
                    inventory.setNodeName(instance.getNodeName());
                    inventory.setStatus(String.valueOf(instance.getStatus()));
                    if(StringUtils.isNotBlank(instance.getUserId())){
                        if(instance.getUserId().indexOf(CommonConstant.SpecialSign.COMMA.getName())!=-1){
                            String[] userIds= instance.getUserId().split(CommonConstant.SpecialSign.COMMA.getName());
                            StringBuilder userName = new StringBuilder();
                            int size = userIds.length;
                            for (int i=0;i< size;i++) {
                                String name = userMap.get(userIds[i])==null?"":userMap.get(userIds[i]).toString();
                                if(i==size-1){
                                    userName.append(name);
                                }else{
                                    userName.append(name).append(CommonConstant.SpecialSign.COMMA.getName());
                                }
                            }
                            inventory.setApproveUserId(instance.getUserId());
                            inventory.setApproveUser(userName.toString());
                        }else{
                            inventory.setApproveUserId(instance.getUserId());
                            inventory.setApproveUser(userMap.get(instance.getUserId())==null?"":userMap.get(instance.getUserId()).toString());
                        }

                    }
                }
            }
        }
        return page;
    }

    @Override
    public void updateStatusById(MaterialCLManagementInventory materialManagementInventory) {
        MaterialCLManagementInventory materialManagementInventory1 = baseMapper.selectById(materialManagementInventory.getId());
        materialManagementInventory1.setPaymentStatus(materialManagementInventory.getPaymentStatus());
        if(CollectionUtils.isNotEmpty(materialManagementInventory.getInventoryItems())){
            inventoryItemService.updateBatchById(materialManagementInventory.getInventoryItems());
        }
        baseMapper.updateById(materialManagementInventory1);
    }


    @Override
    public String saveMaterialManagementInventory(MaterialCLManagementInventory materialManagementInventory) {
        materialManagementInventory.setSpStatus(Constants.ONE_STR);
        baseMapper.insert(materialManagementInventory);
        return materialManagementInventory.getId();
    }

    @Override
    public MaterialCLManagementInventory getDetail(String id) {
        MaterialCLManagementInventory inventory = baseMapper.selectById(id);
        Map<Object, Object> userMap = redisService.hmget(RedisKey.USER_GROUP_TYPE);
        if(userMap!=null){
            inventory.setInspectorName(userMap.get(inventory.getInspectorId())==null?null:userMap.get(inventory.getInspectorId()).toString());
            inventory.setPreparerName(userMap.get(inventory.getPreparerId())==null?null:userMap.get(inventory.getPreparerId()).toString());
            inventory.setArrivalPersonName(userMap.get(inventory.getArrivalPersonId())==null?null:userMap.get(inventory.getArrivalPersonId()).toString());
            inventory.setWarehouseUserName(userMap.get(inventory.getWarehouseUser()) == null ? null : userMap.get(inventory.getWarehouseUser()).toString());
            inventory.setWarehouseSupervisorName(userMap.get(inventory.getWarehouseSupervisor()) == null ? null : userMap.get(inventory.getWarehouseSupervisor()).toString());
        }

        List<MaterialInventoryItem> inventoryItems = inventoryItemService.list(Wrappers.<MaterialInventoryItem>lambdaQuery()
                .eq(MaterialInventoryItem::getInventoryNumber, inventory.getNumber()));
        if(CollectionUtils.isNotEmpty(inventoryItems)){
            inventory.setInventoryItems(inventoryItems);
        }

        return inventory;
    }

    /**
     * 库存计算
     *
     * @param materialManagementInventory
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateInHouse(MaterialCLManagementInventory materialManagementInventory) {
        //检验流程是否结束
        String approveStatus = getApproveStatus(materialManagementInventory.getId());
        if (!StringUtils.equals(approveStatus, Constants.TWO_STR)) {
            throw new ServiceException(MaterialStatusCode.NO_PROCESS_ENDING.getCode(), MaterialStatusCode.NO_PROCESS_ENDING.getMsg());
        }
        MaterialCLManagementInventory materialCLManagementInventory = baseMapper.selectById(materialManagementInventory.getId());

        List<MaterialInventoryItem> materialInventoryItems = inventoryItemService.list(Wrappers.<MaterialInventoryItem>lambdaQuery()
                .eq(MaterialInventoryItem::getInventoryNumber, materialCLManagementInventory.getNumber()));

        if (CollectionUtils.isEmpty(materialInventoryItems)) {
            throw new ServiceException(MaterialStatusCode.NO_ITEM.getCode(), MaterialStatusCode.NO_ITEM.getMsg());
        }

        LocalDateTime now = LocalDateTime.now();
        for (MaterialInventoryItem materialInventoryItem : materialInventoryItems) {
            MaterialALLInventoryManagement one = materialALLInventoryManagementService.getOne(Wrappers.<MaterialALLInventoryManagement>lambdaQuery()
                    .eq(MaterialALLInventoryManagement::getMaterialCode, materialInventoryItem.getItemCode())
                    .eq(MaterialALLInventoryManagement::getWareHouseCode, materialInventoryItem.getWarehouseCode())
                    .eq(MaterialALLInventoryManagement::getStorageLocation,materialInventoryItem.getStorageLocation())
                    .last("limit 1"));
            if (one == null) {
                MaterialALLInventoryManagement materialALLInventoryManagement = new MaterialALLInventoryManagement();
                materialALLInventoryManagement.setMaterialName(materialInventoryItem.getItemName());
                materialALLInventoryManagement.setStockQuantity(materialInventoryItem.getGoodProduct());
                materialALLInventoryManagement.setMaterialId(materialInventoryItem.getItemId());
                materialALLInventoryManagement.setSpecification(materialInventoryItem.getSpecificationModel());
                materialALLInventoryManagement.setBarcodeNumber(materialInventoryItem.getBarcodeNumber());
                materialALLInventoryManagement.setBatchNumber(materialInventoryItem.getPcNumber());
                materialALLInventoryManagement.setStockQuantity(materialInventoryItem.getGoodProduct());
                materialALLInventoryManagement.setUnit(materialInventoryItem.getUnit());
                materialALLInventoryManagement.setProductionDate(materialInventoryItem.getProductDate());
                materialALLInventoryManagement.setSupplier(materialCLManagementInventory.getSupplierId());
                if (materialInventoryItem.getGoodProduct()!=null){
                    materialALLInventoryManagement.setAvailableQuantity(BigDecimal.valueOf(materialInventoryItem.getGoodProduct()));
                }
                materialALLInventoryManagement.setMaterialCode(materialInventoryItem.getItemCode());
                materialALLInventoryManagement.setStorageLocation(materialInventoryItem.getStorageLocation());

                if (materialInventoryItem.getExpiredNum() != null) {
                    materialALLInventoryManagement.setExpirationDate(materialInventoryItem.getExpiredNum().toString());
                }
                materialALLInventoryManagement.setInventoryDate(now);
                materialALLInventoryManagement.setWareHouseCode(materialInventoryItem.getWarehouseCode());
                materialALLInventoryManagement.setWareHouseName(materialInventoryItem.getWarehouseName());
                materialALLInventoryManagement.setWareHouseId(materialCLManagementInventory.getWarehouseId());
                materialALLInventoryManagementService.save(materialALLInventoryManagement);
            } else {
                Integer quality = one.getStockQuantity();
                Integer quantity = materialInventoryItem.getGoodProduct();
                Integer count = quality + quantity;
                one.setStockQuantity(count);
                if (quantity!=null){
                    BigDecimal add = one.getAvailableQuantity().add(BigDecimal.valueOf(quantity));
                    one.setAvailableQuantity(add);
                }
                one.setMaterialName(materialInventoryItem.getItemName());
                materialALLInventoryManagementService.updateById(one);
            }
        }

        materialCLManagementInventory.setCompletionTime(now);
        materialCLManagementInventory.setInStatus(Constants.ONE_STR);
        baseMapper.updateById(materialCLManagementInventory);

        //入库完成后更新到货单入库状态信息
        if(StringUtils.isNotBlank(materialManagementInventory.getPurchaseArrivalNote())){
            purchaseApi.updateStatus(materialManagementInventory.getPurchaseArrivalNote());
        }
    }

    @Override
    public void updateMaterialCLManagementInventory(MaterialCLManagementInventory materialCLManagementInventory) {
        String bpmProcessInstanceStatusStatus = getBpmProcessInstanceStatusStatus(materialCLManagementInventory.getId());
        materialCLManagementInventory.setStatus(bpmProcessInstanceStatusStatus);
        materialCLManagementInventory.setSpStatus(bpmProcessInstanceStatusStatus);
        if(CollectionUtils.isNotEmpty(materialCLManagementInventory.getInventoryItems())){
            inventoryItemService.updateBatchById(materialCLManagementInventory.getInventoryItems());
        }
        baseMapper.updateById(materialCLManagementInventory);
    }

    public String getBpmProcessInstanceStatusStatus(String id) {
        List<String> ids = new ArrayList<>();
        ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(ids);
        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
            Map<String, Integer> statusMap = resultBody.getData().stream().collect(Collectors.toMap(BpmProcessInstanceStatus::getBusinessKey, BpmProcessInstanceStatus::getStatus, (s1, s2) -> s1));
            if (statusMap.get(id) == null) {
                return "";
            } else {
                return statusMap.get(id).toString();
            }
        }
        return "";
    }


    public String getApproveStatus(String id) {
        List<String> ids = new ArrayList<>();
        ids.add(id);
        ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(ids);
        Map<String, String> approveStatusMap = null;
        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
            approveStatusMap = resultBody.getData().stream().collect(Collectors.toMap(BpmProcessInstanceStatus::getBusinessKey, BpmProcessInstanceStatus::getResult, (s1, s2) -> s1));
        }
        if (approveStatusMap.get(id) != null) {
            return approveStatusMap.get(id);
        }
        return "";
    }

}
